package com.cpit.platform.common.utils;

import com.cpit.platform.log.LogOperator;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;

/**
 * Created by gaoju on 2017/10/19.
 */
public class FileUtil {

    private static final String loggerName = FileUtil.class.getClass().getName();

    /**
     * 创建目录，支技多级
     *
     * @param baseDir 基础目录
     * @param moreDir 多个目录，可者用"／" 分隔，如:1."a/b/c"; 也可传多个字符串
     * @return
     */
    public static void createDirectories(String baseDir, String... moreDir) throws IOException {

        Path newdir = FileSystems.getDefault().getPath(baseDir, moreDir);

        LogOperator.debug(loggerName, "baseDir = [" + baseDir + "], moreDir = [" + moreDir + "]");
        try {
            Files.createDirectories(newdir);
        } catch (IOException e) {
            LogOperator.err(loggerName, "createDirectories error!", e);
            throw e;
        }

    }

    /**
     * 强制删除目录
     *
     * @param dir
     * @throws IOException
     */
    public static void forceDeleteDirectories(String dir) throws IOException {
        Path directory = Paths.get(dir);
        DeleteDirectory walk = new DeleteDirectory();
        EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);

        Files.walkFileTree(directory, opts, Integer.MAX_VALUE, walk);
    }

    /**
     * 根据 InputStream 流创建文件
     *
     * @param in
     * @param fileName 新文件名
     * @param toDir
     * @throws IOException
     */
    public static long copyFileToDirByInputStream(InputStream in, String fileName, String toDir) throws IOException {

        Path filePath = Paths.get(toDir, fileName);

        //创建目录
        if (!Files.exists(Paths.get(toDir))) {
            createDirectories(toDir);
        }

        //拷贝
        return Files.copy(in, filePath);
    }


    /**
     * 删除文件
     *
     * @param deleteFilePath
     * @throws IOException
     */
    public static void deleteFileByFilePath(String deleteFilePath) throws IOException {
        Path filePath = Paths.get(deleteFilePath);
        if (!Files.exists(filePath)) {
            throw new IOException("delete file does not exist");
        }
        Files.delete(filePath);
    }


    /**
     * 移动文件
     *
     * @param sourceDir
     * @param sourceFileName
     * @param targetDir
     * @param targetFileName
     * @return
     * @throws IOException
     */
    public static String moveFile(String sourceDir, String sourceFileName,
                                  String targetDir, String targetFileName) throws IOException {

        Path sourcePath = Paths.get(sourceDir, sourceFileName);

        if (!Files.exists(sourcePath)) {
            throw new IOException("source file does not exist");
        }

        Path targetPath = Paths.get(targetDir, targetFileName);

        //创建目录
        if (!Files.exists(Paths.get(targetDir))) {
            createDirectories(targetDir);
        }

        targetPath = Files.move(sourcePath, targetPath);

        return targetPath.toAbsolutePath().toString();
    }

    /**
     * 移动文件
     *
     * @param sourceDir
     * @param sourceFileName
     * @param targetDir
     * @param targetFileName
     * @return
     * @throws IOException
     */
    public static String moveFileReplace(String sourceDir, String sourceFileName,
                                         String targetDir, String targetFileName) throws IOException {

        Path sourcePath = Paths.get(sourceDir, sourceFileName);

        if (!Files.exists(sourcePath)) {
            throw new IOException("source file does not exist");
        }

        Path targetPath = Paths.get(targetDir, targetFileName);

        //创建目录
        if (!Files.exists(Paths.get(targetDir))) {
            createDirectories(targetDir);
        }

        //替换已存在的文件 StandardCopyOption.REPLACE_EXISTING
        targetPath = Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);

        return targetPath.toAbsolutePath().toString();
    }

    /**
     * 拷贝文件
     *
     * @param sourceDir
     * @param sourceFileName
     * @param targetDir
     * @param targetFileName
     * @return
     * @throws IOException
     */
    public static String copyFile(String sourceDir, String sourceFileName,
                                  String targetDir, String targetFileName) throws IOException {

        Path sourcePath = Paths.get(sourceDir, sourceFileName);

        if (!Files.exists(sourcePath)) {
            throw new IOException("source file does not exist");
        }

        Path targetPath = Paths.get(targetDir, targetFileName);

        //创建目录
        if (!Files.exists(Paths.get(targetDir))) {
            createDirectories(targetDir);
        }

        targetPath = Files.copy(sourcePath, targetPath);

        return targetPath.toAbsolutePath().toString();
    }

    /**
     * delete FileVisitor
     */
    static class DeleteDirectory implements FileVisitor {


        @Override
        public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException {
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException {
            boolean success = deleteFileByFile((Path) file);

            if (success) {
                LogOperator.debug(loggerName, "Deleted: " + (Path) file);
            } else {
                LogOperator.debug(loggerName, "Not deleted: " + (Path) file);
            }

            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException {
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException {
            if (exc == null) {
                LogOperator.debug(loggerName, "Visited: " + (Path) dir);
                boolean success = deleteFileByFile((Path) dir);

                if (success) {
                    LogOperator.debug(loggerName, "Deleted: " + (Path) dir);
                } else {
                    LogOperator.debug(loggerName, "Not deleted: " + (Path) dir);
                }
            } else {
                throw exc;
            }
            return FileVisitResult.CONTINUE;
        }

        private boolean deleteFileByFile(Path file) throws IOException {
            return Files.deleteIfExists(file);
        }
    }


}